﻿using Model.Common.ValidateTextBox;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace UserControls.Common
{
    /// <summary>
    /// ValidateTextBox.xaml 的交互逻辑
    /// </summary>
    public partial class ValidateTextBox : TextBox
    {
        public ValidateTextBox()
        {
            InitializeComponent();
            SetValue(ValidationParamsProperty, new FreezableCollection<ValidationParam>());//针对集合类型的依赖项属性,必须加这个,否则会导致创建多个集合项的问题,WPF本身缺陷
            this.Loaded += (o, e) => {
                ValidationResult = ValidateCore(this.Text);//当控件加载完成时执行一次验证
            };
            this.PreviewTextInput += (o, e) => _cursorPos = this.SelectionStart;
            this.PreviewKeyDown += (o, e) => _cursorPos = this.SelectionStart;
            this.GotKeyboardFocus += (o, e) => _oldValue = this.Text;
        }


        private string _oldValue = null;//保存最后一次通过验证的值,以用于回滚
        private int _cursorPos;//记录变更之前光标的位置

        protected override void OnTextChanged(TextChangedEventArgs e)
        {
            ValidationResult = ValidateCore(this.Text);
            if ((Mode == ValidateTextBoxMode.Restriction) && (ValidationResult.IsValid == false))
            {
                if (ValidateCore(_oldValue).IsValid)
                {
                    Text = _oldValue;
                    this.SelectionStart = _cursorPos;
                    return;
                }
                else if (ValidateCore(DefaultText).IsValid)
                {
                    Text = DefaultText;
                    _oldValue = DefaultText;
                    this.SelectionStart = Text.Length;
                    return;
                }
                else
                    throw new Exception("DefaultText值无法使用,因为它无法通过验证!");
            }
            _oldValue = Text;
            base.OnTextChanged(e);
        }

        /// <summary>
        /// 是否启用限制输入模式
        /// </summary>
        public ValidateTextBoxMode Mode
        {
            get { return (ValidateTextBoxMode)GetValue(ModeProperty); }
            set { SetValue(ModeProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Mode.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ModeProperty =
            DependencyProperty.Register("Mode", typeof(ValidateTextBoxMode), typeof(ValidateTextBox), new FrameworkPropertyMetadata(ValidateTextBoxMode.Validation, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnModeChanged));

        private static void OnModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            InputMethod.SetIsInputMethodEnabled(d, !e.NewValue.Equals(ValidateTextBoxMode.Restriction));//当使用Restriction模式时，禁用输入法
        }

        /// <summary>
        /// 文本框的默认值
        /// </summary>
        public string DefaultText
        {
            get { return (string)GetValue(DefaultTextProperty); }
            set { SetValue(DefaultTextProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DefaultText.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DefaultTextProperty =
            DependencyProperty.Register("DefaultText", typeof(string), typeof(ValidateTextBox), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));



        /// <summary>
        /// 文本框输入的内容描述
        /// </summary>
        public string Description
        {
            get { return (string)GetValue(DescriptionProperty); }
            set { SetValue(DescriptionProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Description.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DescriptionProperty =
            DependencyProperty.Register("Description", typeof(string), typeof(ValidateTextBox), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, Validate));


        /// <summary>
        /// 验证分组
        /// </summary>
        public string GroupName
        {
            get { return (string)GetValue(GroupNameProperty); }
            set { SetValue(GroupNameProperty, value); }
        }

        // Using a DependencyProperty as the backing store for GroupName.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty GroupNameProperty =
            DependencyProperty.Register("GroupName", typeof(string), typeof(ValidateTextBox), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));


        /// <summary>
        /// 验证参数
        /// </summary>
        public FreezableCollection<ValidationParam> ValidationParams
        {
            get { return (FreezableCollection<ValidationParam>)GetValue(ValidationParamsProperty); }
        }

        // Using a DependencyProperty as the backing store for ValidationParams.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValidationParamsProperty =
            DependencyProperty.Register("ValidationParams", typeof(FreezableCollection<ValidationParam>), typeof(ValidateTextBox), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, Validate));



        /// <summary>
        /// 验证器
        /// </summary>
        public ValidatorBase Validator
        {
            get { return (ValidatorBase)GetValue(ValidatorProperty); }
            set { SetValue(ValidatorProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Validator.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValidatorProperty =
            DependencyProperty.Register("Validator", typeof(ValidatorBase), typeof(ValidateTextBox), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, Validate));

        /// <summary>
        /// 正则表达式验证
        /// </summary>
        public string RegxPatten
        {
            get { return (string)GetValue(RegxPattenProperty); }
            set { SetValue(RegxPattenProperty, value); }
        }

        // Using a DependencyProperty as the backing store for RexPatten.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RegxPattenProperty =
            DependencyProperty.Register("RegxPatten", typeof(string), typeof(ValidateTextBox), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, Validate));


        /// <summary>
        /// 正则表达式验证错误信息
        /// </summary>
        public string RegxValidateErrorMessage
        {
            get { return (string)GetValue(RegxValidateErrorMessageProperty); }
            set { SetValue(RegxValidateErrorMessageProperty, value); }
        }

        // Using a DependencyProperty as the backing store for RegxValidateErrorMessage.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RegxValidateErrorMessageProperty =
            DependencyProperty.Register("RegxValidateErrorMessage", typeof(string), typeof(ValidateTextBox), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, Validate));


        /// <summary>
        /// 内容是否是必填项
        /// </summary>
        public bool IsRequired
        {
            get { return (bool)GetValue(IsRequiredProperty); }
            set { SetValue(IsRequiredProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsRequired.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsRequiredProperty =
            DependencyProperty.Register("IsRequired", typeof(bool), typeof(ValidateTextBox), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, Validate));

        /// <summary>
        /// 当内容为必填项此用户未输入时的提示内容
        /// </summary>
        public string RequiredErrorMessage
        {
            get { return (string)GetValue(RequiredErrorMessageProperty); }
            set { SetValue(RequiredErrorMessageProperty, value); }
        }

        // Using a DependencyProperty as the backing store for RequiredErrorMessage.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RequiredErrorMessageProperty =
            DependencyProperty.Register("RequiredErrorMessage", typeof(string), typeof(ValidateTextBox), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, Validate));

        /// <summary>
        /// 验证环境发生变化时此方法执行以更新验证
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void Validate(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ValidateTextBox textBox = d as ValidateTextBox;
            if (textBox.IsLoaded)
                textBox.ValidationResult = textBox.ValidateCore(textBox.Text);
        }


        /// <summary>
        /// 控件的验证结果
        /// </summary>
        public ValidateResult ValidationResult
        {
            get { return (ValidateResult)GetValue(ValidationResultProperty.DependencyProperty); }
            private set { SetValue(ValidationResultProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ValidationResult.  This enables animation, styling, binding, etc...
        public static readonly DependencyPropertyKey ValidationResultProperty =
            DependencyProperty.RegisterReadOnly("ValidationResult", typeof(ValidateResult), typeof(ValidateTextBox), new PropertyMetadata(new ValidateResult(true, null)));


        /// <summary>
        /// 核心验证方法
        /// </summary>
        private ValidateResult ValidateCore(string ValidateText)
        {
            ValidateResult result;
            //空值和null验证
            if (IsRequired && string.IsNullOrWhiteSpace(ValidateText))
            {
                result = new ValidateResult(false, RequiredErrorMessage);
                result.Description = Description;
                return result;
            }
            //正则表达式判定
            if (!(string.IsNullOrWhiteSpace(RegxPatten) || string.IsNullOrWhiteSpace(ValidateText)))
            {
                bool isValid = Regex.IsMatch(ValidateText, RegxPatten);
                result = new ValidateResult(isValid, RegxValidateErrorMessage);
                result.Description = Description;
                if (!result.IsValid)
                {
                    return result;
                }
            }
            //进行自定义方法验证
            if (Validator != null)
            {
                object[] param = null;
                param = ValidationParams.Select(vp => vp.Binding).ToArray();
                result = Validator.Validate(ValidateText, param);
                result.Description = Description;
                if (!result.IsValid)
                {
                    return result;
                }
            }
            //验证通过
            result = new ValidateResult(true, null);
            result.Description = Description;
            return result;
        }
    }
   
    public class ValidationParam : Freezable
    {
        public object Binding
        {
            get { return (object)GetValue(BindingProperty); }
            set { SetValue(BindingProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Binding.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty BindingProperty =
            DependencyProperty.Register("Binding", typeof(object), typeof(ValidationParam), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

        protected override Freezable CreateInstanceCore()
        {
            return new ValidationParam();
        }
    }
    public enum ValidateTextBoxMode
    {
        Validation, Restriction,Password
    }
}
